package com.dounine.search;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by huanghuanlai on 16/4/12.
 */
public class SearchAccount implements Runnable {

    public static HttpPost request = null;
    public static int findAccount = 0;
    public static CloseableHttpClient httpClient = HttpClients.custom()
            .setDefaultRequestConfig(RequestConfig.custom()
                    .setSocketTimeout(2000)
                    .setConnectTimeout(10000)//代理连接超时时间
                    .setConnectionRequestTimeout(2000)
                    .build()).build();
    public static Connection con = null;
    public static final String url = "jdbc:mysql://101.200.198.169/lake";
    public static long findCount = 0;
    public static long saveCount = 0;
    public static long notCount = 0;
    public static HttpHost proxy = null;
    public static boolean useProxy = false;
    public static Pattern pattern = Pattern.compile("[a-z]{7,7}");

    public static void loadRequest(){
        Statement stmt = null;
        List<Map> list = new ArrayList();
        ResultSet rs = null;
        try {
            con = DriverManager.getConnection(url, "root", "BJIKE++..");
            stmt = con.createStatement();
            rs = stmt.executeQuery("select id,url,cookie from cookie");
            ResultSetMetaData md = rs.getMetaData();
            int columnCount = md.getColumnCount();
            while(rs.next()){
                Map map = new HashMap();
                for (int i = 1; i <= columnCount; i++) {
                    map.put(md.getColumnName(i), rs.getObject(i));
                }
                list.add(map);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(null!=stmt){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(null!=rs){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(null!=con){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        if(list.size()!=0){
            Map map = list.get(0);
            if(null!=map){
                ConsoleProgressBar.changeTxt(" 开始构建请求");
                String requestUrl = String.valueOf(map.get("url"));
                String cookieValue = String.valueOf(map.get("cookie"));
                request = new HttpPost(requestUrl);
                request.setHeader("Cookie", cookieValue);
                request.setHeader("X-QIHOO-HOST", "api.photo.yunpan.360.cn");
                request.setHeader("Accept-Encoding", "zip");
                request.setHeader("Host", "api.photo.yunpan.360.cn");
                request.setHeader("Charset", "UTF-8");
                request.setHeader("User-Agent", "Dalvik/1.6.0 (Linux; U; Android 4.3; Custom Phone - 4.3 - API 18 - 768x1280 Build/JLS36G)");
                request.setHeader("Connection", "Keep-Alive");

                ConsoleProgressBar.changeTxt(" 请求构建完毕");
            }else{
                ConsoleProgressBar.changeTxt(" 程序查不到cookie数据,程序结束");
                System.exit(0);
            }
        }else{
            ConsoleProgressBar.changeTxt(" 程序查不到cookie数据,程序结束");
            System.exit(0);
        }
    }

    static {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ConsoleProgressBar cpb = new ConsoleProgressBar();
                cpb.begin();
            }
        }).start();
        try {
            ConsoleProgressBar.changeTxt(" 开始加载数据库驱动程序");
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            ConsoleProgressBar.changeTxt(" 加载数据库驱动程序完成");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        loadRequest();
    }

    public static void main(String args[]) {
        SearchAccount searchAccount = new SearchAccount();
        if(null!=args&&args.length>0){
            useProxy = Boolean.valueOf(args[0]);
        }
        new Thread(searchAccount).start();
    }

    @Override
    public void run() {
        boolean b = true;
        while (b) {
            List<NameValuePair> valuePairs = new ArrayList<>();
            String account = AccountRandom.random();
            valuePairs.add(new BasicNameValuePair("username", account));
            request.setEntity(new UrlEncodedFormEntity(valuePairs, Consts.UTF_8));
            CloseableHttpResponse response = null;
            PreparedStatement pstmt = null;
            Statement statement = null;
            try {
                response = httpClient.execute(request);
                String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
                if (result.contains("\\u627e\\u4e0d\\u5230\\u8be5\\u7528\\u6237")) {
                    notCount++;
                    ConsoleProgressBar.changeTxt(" 本程序已经搜索到[ "+findCount+" : "+notCount+" ]用户;搜索当中");
                } else {
                    if (result.contains("\\u64cd\\u4f5c\\u592a\\u5feb\\u4e86, \\u4f11\\u606f\\u4e00\\u4f1a\\u5427")) {
                        ConsoleProgressBar.changeTxt(" 本程序已经搜索到[ "+findCount+" : "+notCount+" ]用户;搜索频繁,暂停当中");
                        if(useProxy){
                            //Thread.sleep(1000 * 60);
                            con = DriverManager.getConnection(url, "root", "BJIKE++..");
                            statement = con.createStatement();
                            if(null!=proxy){
                                pstmt = con.prepareStatement("select failure_count from proxy where ip_value=? and ip_port=?");
                                pstmt.setString(1,proxy.getHostName());
                                pstmt.setInt(2,proxy.getPort());
                                ResultSet rs = pstmt.executeQuery();
                                int failure_count = 0;
                                if(rs.next())
                                {
                                    failure_count=rs.getInt("failure_count");
                                }

                                pstmt = con.prepareStatement("update proxy set failure_count=?,updateTime=? where ip_value=? and ip_port=?");
                                pstmt.setInt(1,++failure_count);//uuid
                                pstmt.setLong(2,System.currentTimeMillis());//uuid
                                pstmt.setString(3,proxy.getHostName());
                                pstmt.setInt(4,proxy.getPort());
                                int i =pstmt.executeUpdate();
                                ConsoleProgressBar.changeTxt(" 更新ip频繁次数");
                            }

                            ResultSet rs = statement.executeQuery("select ip_value,ip_port from proxy ORDER BY `updateTime` ASC limit 0,1");
                            boolean hasProxy = true;
                            if(rs.next()) {
                                String ip_val = rs.getString("ip_value");
                                Integer port_val = rs.getInt("ip_port");
                                ConsoleProgressBar.changeTxt(" 切换代理:"+ip_val+":"+port_val);
                                proxy = new HttpHost(ip_val,port_val);
                                httpClient = HttpClients.custom()
                                        .setDefaultRequestConfig(RequestConfig.custom()
                                                .setProxy(proxy)
                                                .setSocketTimeout(10000)
                                                .setConnectTimeout(10000)
                                                .setConnectionRequestTimeout(2000)
                                                .build()).build();
                            }
                        }else{
                            Thread.sleep(1000*60);
                        }
                    } else if (result.contains("\\u7528\\u6237\\u672a\\u767b\\u5f55\\u6216\\u8ba4\\u8bc1\\u4fe1\\u606f\\u9519\\u8bef")) {
                        ConsoleProgressBar.changeTxt(" 用户未登录或认证信息错误");
                        Thread.sleep(3000);
                        ConsoleProgressBar.changeTxt(" 等待重新获取认证信息");
                        Thread.sleep(1000*60);
                        loadRequest();
                    } else {
                        Account accountObj = JSON.parseObject(result, Account.class);
                        if(null!=accountObj){
                            AccountList accountList = accountObj.getData().getList().get(0);
                            if (null!=accountList&&StringUtils.isBlank(accountList.getLoginEmail())&&pattern.matcher(accountList.getUserName()).matches()) {
                                findCount++;
                                ConsoleProgressBar.changeTxt(" 本程序已经搜索到[ "+findCount+" : "+notCount+" ]用户;搜索当中");
                                con = DriverManager.getConnection(url, "root", "BJIKE++..");
                                if(null!=con){
                                    statement = con.createStatement();
                                    ResultSet rs = statement.executeQuery("select count(1) as record_ from search where account='"+accountObj.getData().getList().get(0).getUserName()+"'");
                                    int rowCount = 0;
                                    if(rs.next())
                                    {
                                        rowCount=rs.getInt("record_");
                                    }
                                    if(rowCount==0){
                                        pstmt = con.prepareStatement("insert into search(id,account,result,createTime)values(?,?,?,?);");
                                        pstmt.setString(1, String.valueOf(UUID.randomUUID()));//uuid
                                        pstmt.setString(2,accountObj.getData().getList().get(0).getUserName());
                                        pstmt.setString(3,result);
                                        pstmt.setString(4, LocalDateTime.now().toString());
                                        int i =pstmt.executeUpdate();
                                        if(i>0){
                                            saveCount++;
                                        }else{
                                            ConsoleProgressBar.changeTxt(" 保存失败,存储到本地");
                                            //FileUtils.writeStringToFile(file,result,true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                if (e instanceof SocketTimeoutException) {
                    //e.printStackTrace();
                    //连接超时
                } else if (e instanceof NoHttpResponseException) {
                    //请求错误
                }else if(e instanceof UnknownHostException){
                    //断网,不认识主机地址
                } else if (e instanceof SocketException) {
                    //断网
                }else if(e instanceof ConnectTimeoutException){
                    //代理连接超时
                    if(useProxy){
                        ConsoleProgressBar.changeTxt(" 代理连接超时");
                        try {

                            if(null!=proxy){
                                con = DriverManager.getConnection(url, "root", "BJIKE++..");
                                statement = con.createStatement();

                                pstmt = con.prepareStatement("select failure_count from proxy where ip_value=? and ip_port=?");
                                pstmt.setString(1,proxy.getHostName());
                                pstmt.setInt(2,proxy.getPort());
                                ResultSet rs = pstmt.executeQuery();
                                int failure_count = 0;
                                if(rs.next())
                                {
                                    failure_count=rs.getInt("failure_count");
                                }

                                pstmt = con.prepareStatement("update proxy set failure_count=?,updateTime=? where ip_value=? and ip_port=?");
                                pstmt.setInt(1,++failure_count);//uuid
                                pstmt.setLong(2,System.currentTimeMillis());//uuid
                                pstmt.setString(3,proxy.getHostName());
                                pstmt.setInt(4,proxy.getPort());
                                int i =pstmt.executeUpdate();

                                rs = statement.executeQuery("select ip_value,ip_port from proxy ORDER BY `updateTime` ASC limit 0,1");
                                boolean hasProxy = true;
                                if(rs.next()) {
                                    proxy = new HttpHost(rs.getString("ip_value"),rs.getInt("ip_port"));
                                    httpClient = HttpClients.custom()
                                            .setDefaultRequestConfig(RequestConfig.custom()
                                                    .setProxy(proxy)
                                                    .setSocketTimeout(10000)
                                                    .setConnectTimeout(10000)
                                                    .setConnectionRequestTimeout(2000)
                                                    .build()).build();
                                }
                                if(!hasProxy){
                                    httpClient = HttpClients.custom()
                                            .setDefaultRequestConfig(RequestConfig.custom()
                                                    .setSocketTimeout(2000)
                                                    .setConnectTimeout(2000)
                                                    .setConnectionRequestTimeout(2000)
                                                    .build()).build();
                                }
                            }
                        }catch (Exception e1){

                        }
                    }

                } else {
                    e.printStackTrace();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                //e.printStackTrace();
            } finally {
                if (null != response) {
                    try {
                        response.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(null!=pstmt){
                    try {
                        pstmt.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(null!=statement){
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(null!=con){
                    try {
                        con.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
